iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 12
0
自我挑戰組

打造專案管理 iOS App 系列 第 12

一個與網路的心靈獨白 利用multipart form-data上傳相片

  • 分享至 

  • xImage
  •  

一個與網路的心靈獨白 利用multipart form-data上傳相片

或許你已經非常了解如何利用Json上傳資料,但是不知道你是否思考過。

如何上傳檔案呢?

Json是沒辦法上傳檔案的,如果需要上傳檔案,那就需要使用其他的ContentType。

網路請求有哪些選擇?

發出POST請求時,必須以某種方式對構成請求正文的數據進行編碼。

HTML表單提供了三種編碼方法。

  • application/x-www-form-urlencoded (默認)
  • multipart/form-data
  • text/plain

(使用HTML表單提交以外的其他方式生成的HTTP請求也可以使用其他編碼。JSON是用於Web服務的常見格式,有些仍然使用SOAP。)

multipart/form-data

以下是很典型的multipart/form-data的樣式

POST / HTTP/1.1
[[ Less interesting headers ... ]]
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150
Content-Length: 834

-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="text1"

text default
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="text2"

aωb
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file1"; filename="a.txt"
Content-Type: text/plain

Content of a.txt.

-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file2"; filename="a.html"
Content-Type: text/html

<!DOCTYPE html><title>Content of a.html.</title>

-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file3"; filename="binary"
Content-Type: application/octet-stream

aωb
-----------------------------735323031399963166993862150--

對於二進製文件和文本字段,字節61 CF 89 62(aωb在UTF-8中)按字面意義發送。您可以使用驗證該信息nc -l localhost 8000 | hd,該信息表明這些字節:

Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150將內容類型設置為,multipart/form-data並說字段由給定的boundary字符串分隔。

swift 實作 multipart/form-data 上傳

multipart/form-data與往前的json略顯不同,我將拆解的部分做了一些變化。

  1. 生成 parameters(組裝要上傳的參數)
  2. 生成 dataPaths(組裝要上傳的檔案)
  3. 生成 Body,並打包 parameters 與 dataPaths
  4. 生成 request

生成 parameters

製作一個生成parameters的funtion

 static func makeParameters(_ cardID:Int,_ view:CardEditView,_ method:HTTPMethod)->[String:Any]{
        var parameters:[String:Any] = [:]
        let data = getViewData(view: view)
        if let title = data.title {
            parameters["title"] = title
        }
        if let description = data.description {
            parameters["description"] = description
        }
        if method == .PUT {
        parameters["_method"] = "PUT"
        }
        parameters["card_id"] = cardID
        parameters["tag"] = data.tag
        print(parameters)
        return parameters
    }

生成 DataPaths

製作一個生成DataPaths 的 funtion

var dataPath:[String:Data] = [:]
            let data = getViewData(view: view)
            if let image = data.image {
                let data = image.jpegData(compressionQuality: 0.1)
                dataPath["image"] = data
            }
            return dataPath

生成 Body

生成 Body,並打包 parameters 與 dataPaths

private static func makeBody(_ parameters:[String:Any],_ dataPath:[String:Data],_ boundary:String)->Data{
        var body = Data()
        
        for (key, value) in parameters {
            body.appendString(string: "--\(boundary)\r\n")
            body.appendString(string: "Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
            body.appendString(string: "\(value)\r\n")
        }
        for (key, value) in dataPath {
            body.appendString(string: "--\(boundary)\r\n")
            body.appendString(string: "Content-Disposition: form-data; name=\"\(key)\"; filename=\"\(arc4random())\"\r\n") //此處放入file name,以隨機數代替,可自行放入
            body.appendString(string: "Content-Type: image/png\r\n\r\n") //image/png 可改為其他檔案類型 ex:jpeg
            body.append(value)
            body.appendString(string: "\r\n")
        }
        
        body.appendString(string: "--\(boundary)--\r\n")
         return body
     }

在這裡你不能發現boundary,這個東西類似,分隔線。

你需要特別注意,boundary必須都是一樣的,另外,設置content Type時,是要帶給header的。
所以在生成request時,可以額外打包給他。


上一篇
一個與網路的心靈獨白 網路請求
下一篇
一個與網路的心靈獨白 URL轉Image
系列文
打造專案管理 iOS App 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言